package ua.kiev.tosik.price.modules.clients.gui.files.preview;

import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXPanel;
import ua.kiev.tosik.price.models.Prices;
import ua.kiev.tosik.price.models.PricesFiles;
import ua.kiev.tosik.price.modules.clients.conf.FilterConfig;
import ua.kiev.tosik.price.modules.clients.conf.ModuleConfig;
import ua.kiev.tosik.price.modules.clients.database.prices.PricesSaveWorker;
import ua.kiev.tosik.price.modules.clients.gui.files.IPricesTab;
import ua.kiev.tosik.price.modules.clients.gui.prices.PricesDialog;
import ua.kiev.tosik.price.modules.clients.models.ExcelData;
import ua.kiev.tosik.price.modules.clients.models.FilterAction;
import ua.kiev.tosik.price.modules.clients.tools.ExcelParser;
import ua.kiev.tosik.price.modules.clients.tools.IPriceValidator;

import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * This is panel for output Raw Excel Table
 */
public class PricesFilesPreviewPanel implements IPricesTab, PropertyChangeListener {

	private static Logger logger = Logger.getLogger("ua.kiev.tosik.price.modules.clients.gui.files.preview");
	private JXPanel panel;
	private ModuleConfig config;
	private PricesFilesPreviewTable table;
	private PricesFilesFilterPanel filterPanel;
	private int selectedColumn = -1;
	private PricesFiles pricesFiles;
	private Vector<Object[]> tableData;
	private Vector<Object[]> fullData;

	public PricesFilesPreviewPanel() {
		config = ModuleConfig.getInstance();
		panel = new JXPanel(new BorderLayout());
		table = new PricesFilesPreviewTable(this);
		filterPanel = new PricesFilesFilterPanel(this);
		filterPanel.setCollapsed(true);
		panel.add(filterPanel, BorderLayout.NORTH);
		panel.add(table.getTable(), BorderLayout.CENTER);
	}

	@Override
	public void destroy() {
		tableData = null;
		fullData = null;
		filterPanel = null;
		table = null;
		panel = null;
	}

	@Override
	public String getTitle() {
		return config.get("clients.files.tab.preview.title");
	}

	@Override
	public ImageIcon getImageIcon() {
		return new ImageIcon(config.get("clients.files.tab.preview.icon"));
	}

	@Override
	public JComponent getPanel() {
		return panel;
	}

	@Override
	@SuppressWarnings("unchecked")
	public void propertyChange(PropertyChangeEvent evt) {
		if (evt.getPropertyName().equals("PARSE_START")) {
			PricesDialog.getInstance().getStatusBar().setWait();
		}
		if (evt.getPropertyName().equals("PARSE_DONE")) {
			PricesDialog.getInstance().getStatusBar().reset();
		}
		if (evt.getPropertyName().equals("PARSE_OK")) {
			Vector<ExcelData> allData = (Vector<ExcelData>)evt.getNewValue();
			WeakReference<Vector<ExcelData>> wr = new WeakReference<Vector<ExcelData>>(allData);
			if ( allData.size() > 0 ) {
				ExcelData data = allData.get(0);
				if ( data.getColumns().length > 0 ) {
					table.getModel().setColNames(data.getColumns());
					table.getModel().fireTableStructureChanged();
					table.getModel().addRowSet(100, data.getData());
					fullData = data.getData();
					table.initHeaderRender();
					tableData = new Vector<Object[]>(table.getModel().getData());
				}
			}
			allData = null;
		}
		if (evt.getPropertyName().equals("PARSE_ERROR")) {
			Exception e = (Exception) evt.getNewValue();
			String title = config.get("clients.editor.message.error");
			String message = e.getLocalizedMessage();
			String details = e.getLocalizedMessage();
			PricesDialog.getInstance().showMessageDialog(title, message, details);
		}
		if (evt.getPropertyName().equals("SAVE_START")) {
			setLockPanel(true);
			PricesDialog.getInstance().getStatusBar().setWait(config.get("clients.files.tab.preview.status.progress.saving.text"));
			PricesDialog.getInstance().getStatusBar().setProgressString(config.get("clients.files.tab.preview.status.progress.saving.text"));
			PricesDialog.getInstance().getStatusBar().setProgressValue(0);
			PricesDialog.getInstance().getStatusBar().setProgressMax(fullData.size());
			PricesDialog.getInstance().getStatusBar().showProgress(true);
		}
		if (evt.getPropertyName().equals("SAVE_RECORD_COUNT")) {
			PricesDialog.getInstance().getStatusBar().setProgressValue((Integer)evt.getNewValue());
		}
		if (evt.getPropertyName().equals("SAVE_DONE")) {
			setLockPanel(false);
			PricesDialog.getInstance().getStatusBar().reset();
			logger.debug("SaveWorker done with " + evt.getNewValue() + " record(s)");
		}
		if (evt.getPropertyName().equals("SAVE_OK")) {
			setLockPanel(false);
			PricesDialog.getInstance().getStatusBar().reset();
			pricesFiles.setParsed(true);
			PricesDialog.getInstance().getCenterPanel().removeTab(this);
			MessageFormat fmt = new MessageFormat(config.get("clients.files.tab.preview.saveOk.message"));
			Object[] tmp = {evt.getNewValue(), evt.getOldValue()};
			JOptionPane.showMessageDialog(PricesDialog.getInstance().getCenterPanel().getCenterPanel(), fmt.format(tmp), config.get("clients.files.tab.preview.saveOk.title"), JOptionPane.INFORMATION_MESSAGE, new ImageIcon(config.get("clients.files.tab.preview.saveOk.icon")));
			logger.debug("Save done!");
		}
		if (evt.getPropertyName().equals("SAVE_ERROR")) {
			setLockPanel(false);
			PricesDialog.getInstance().getStatusBar().reset();
			Exception e = (Exception) evt.getNewValue();
			String title = config.get("clients.editor.message.error");
			String message = e.getLocalizedMessage();
			String details = e.getLocalizedMessage();
			PricesDialog.getInstance().showMessageDialog(title, message, details);
		}

	}

	public void setLockPanel(boolean lock) {
		PricesDialog.getInstance().setLockDialog(lock);
		filterPanel.setEnableButton(!lock);
	}

	public void openFilterPanel(int selectedColumn) {
		this.selectedColumn = selectedColumn;
		if (filterPanel.isCollapsed()) {
			filterPanel.setCollapsed(false);
		}
	}

	public void setSelectedColTo(Object title) {
		if ( table.getModel().getData().size() > 0 && selectedColumn >= 0 ) {
			if (table.getHeaderObject(selectedColumn) == title) {
				logger.debug("Clear header marker");
				table.setColumnName(selectedColumn, "Column " + (selectedColumn + 1));
				verifyTableData();
				return;
			}
		}
		clearHeaderMarker(title);
		if ( table.getModel().getData().size() > 0 && selectedColumn >= 0 ) {
			table.setColumnName(selectedColumn, title);
		}
		verifyTableData();
	}

	private void clearHeaderMarker(Object title) {
		for (int i = 0; i < table.getModel().getColumnCount(); i++) {
			if (table.getHeaderObject(i) == title) {
				table.setColumnName(i, "Column " + (i + 1));
				break;
			}
		}
	}

	public void verifyTableData() {
		Vector<Object[]> tmpData = new Vector<Object[]>();
		for (Object[] row : tableData) {
			boolean correctRow = true;
			for (int i = 0; i < table.getModel().getColumnCount(); i++) {
				if (table.getHeaderObject(i) instanceof FilterAction) {
					IPriceValidator validator = ((FilterAction) table.getHeaderObject(i)).getValidator();
					if (!validator.isValid(row[i])) {
						// logger.debug(validator.getClass().getSimpleName() + ": row " + row[i] + " has invalid value");
						correctRow = false;
						break;
					}
				}
			}
			if ( correctRow ) {
				tmpData.add(row);
			}
		}
		if ( tmpData.size() != table.getModel().getData().size() ) {
			table.getModel().addRowSet(tmpData);
			selectedColumn = -1;
		}
	}

	public void setPricesFiles(PricesFiles pricesFiles) {
		this.pricesFiles = pricesFiles;
	}

	public void savePrices() {
		if ( fullData == null || fullData.size() == 0 ) {
			logger.debug("Nothing to save");
			return;
		}

		for ( FilterAction action: FilterConfig.getInstance().getFilters() ) {
			if ( action.isRequired() && !isInHeader(action) ) {
				Object[] fieldName = {action.getName()};
				MessageFormat fmt = new MessageFormat(config.get("clients.files.tab.preview.filter.button.save.requiredField.error"));
				PricesDialog.getInstance().showMessageDialog(config.get("clients.editor.message.error"), fmt.format(fieldName), fmt.format(fieldName));
				return;
			}
		}

		List<Prices> pricesList = new ArrayList<Prices>();
		for ( Object[] row : fullData ) {
			boolean correctRow = true;
			Prices prices = new Prices();
			for ( int i = 0; i < table.getModel().getColumnCount(); i++ ) {
				if ( table.getHeaderObject(i) instanceof FilterAction ) {
					IPriceValidator validator = ((FilterAction) table.getHeaderObject(i)).getValidator();
					if ( !validator.isValid(row[i]) ) {
						correctRow = false;
						break;
					} else {
						prices = validator.fillData(prices, row[i]);
					}
				}
			}
			if ( correctRow ) {
				prices.setClientsId(pricesFiles.getClientsId());
				prices.setPricesFilesId(pricesFiles.getId());
				prices.setPricesDate(pricesFiles.getPricesDate());
				pricesList.add(prices);
			}
		}
		logger.debug("Found " + pricesList.size() + " correct record(s) from " + fullData.size() + " amount in Excel");
		PricesSaveWorker saveWorker = new PricesSaveWorker();
		saveWorker.setPricesFiles(pricesFiles);
		saveWorker.setPricesList(pricesList);
		saveWorker.addPropertyChangeListener(this);
		saveWorker.execute();
	}

	private boolean isInHeader(FilterAction action) {
		for ( int i = 0; i < table.getModel().getColumnCount(); i++ ) {
			if ( table.getHeaderObject(i) instanceof FilterAction ) {
				if ( ((FilterAction)table.getHeaderObject(i)).getId().equals(action.getId()) ) {
					return true;
				}
			}
		}
		return false;
	}

}
